#include "WorkerThread.h"
#include <e32debug.h>
#include <ecom.h>
#include <FunTrace.h>
#include "Binder.h"
#include "SingaporeBusDocument.h"
#include <aknglobalnote.h> 

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }

extern RFile sRemoteLogFile;

struct CLocalThreadCallback : public CActive
	{
	RMsgQueue< scalp::CFunction<void()>* >& iLocalMsgQueue;
	CLocalThreadCallback(RMsgQueue< scalp::CFunction<void()>* >& aLocalMsgQueue) : iLocalMsgQueue(aLocalMsgQueue), CActive(CActive::EPriorityHigh)
		{
		CActiveScheduler::Add(this);
		}
	void Listen()
		{
		TFunTrace funTrace(__PRETTY_FUNCTION__);
		iLocalMsgQueue.NotifyDataAvailable(iStatus);
		SetActive();
		}
	void RunL()
		{
		TFunTrace funTrace(__PRETTY_FUNCTION__);
		scalp::CFunction<void()>* function;
		if ( iStatus.Int() == KErrNone ) 
			{
			while(iLocalMsgQueue.Receive(function) == KErrNone)
				delete function;
			}
		Listen();
		}
	void DeleteAll()
		{
		TFunTrace funTrace(__PRETTY_FUNCTION__);
		scalp::CFunction<void()>* function;
		while(iLocalMsgQueue.Receive(function) == KErrNone)
			delete function;
		}
	void DoCancel()
		{
		TFunTrace funTrace(__PRETTY_FUNCTION__);
		iLocalMsgQueue.CancelDataAvailable();
		}
	};


void CWorkerThread::Start(scalp::CFunction<void()>* aFunction)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iInitFunction = aFunction;
	iMainThreadId = RThread().Id();
	User::LeaveIfError( iLocalMsgQueue.CreateLocal(1024) );
	/*iLocalThreadCallback = new(ELeave) CLocalThreadCallback(iLocalMsgQueue);
	iLocalThreadCallback->Listen();*/
	User::LeaveIfError( iWorkerThread.Create(KNullDesC, &ThreadFunction, KDefaultStackSize, NULL, this) );
	iWorkerThread.SetPriority(EPriorityLess);
	iWorkerThread.Rendezvous(iThreadInitStatus);
	iWorkerThread.Resume();
	User::WaitForRequest(iThreadInitStatus);
	}



void CWorkerThread::TerminateThread()
	{
	// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
	iTerminateThread = ETrue;
	}

void CWorkerThread::Stop()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TRequestStatus logonReq;
	iWorkerThread.Logon(logonReq);
	iMsgQueue.SendBlocking( scalp::MakeFunctionL( scalp::Bind(&CWorkerThread::TerminateThread, this) ) );	
	User::WaitForRequest(logonReq);
	iWorkerThread.Close();

	{
	scalp::CFunction<void()>* function;
	while(iLocalMsgQueue.Receive(function) == KErrNone)
		delete function;
	}

	/*
	iLocalThreadCallback->DeleteAll();
	iLocalThreadCallback->Cancel();
	delete iLocalThreadCallback;*/
	iLocalMsgQueue.Close();
	}



struct CThreadCallback : public CActive
	{
	RMsgQueue< scalp::CFunction<void()>* >& iMsgQueue;
	RMsgQueue< scalp::CFunction<void()>* >& iLocalMsgQueue; // used for deleting only
	TBool* iTerminateThread;
	CThreadCallback(TBool* aTerminateThread, RMsgQueue< scalp::CFunction<void()>* >& aMsgQueue, RMsgQueue< scalp::CFunction<void()>* >& aLocalMsgQueue) : iLocalMsgQueue(aLocalMsgQueue), iTerminateThread(aTerminateThread), iMsgQueue(aMsgQueue), CActive(CActive::EPriorityStandard)
		{
		CActiveScheduler::Add(this);
		}
	void Listen()
		{
		// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
		iMsgQueue.NotifyDataAvailable(iStatus);
		SetActive();
		}
	void RunL()
		{
		// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
		scalp::CFunction<void()>* function;
		if ( iStatus.Int() == KErrNone ) 
			{
			while(iMsgQueue.Receive(function) == KErrNone)
				{
				TRAPD(err, (*function)());
				if(err != KErrNone)
					RDebug::Print(_L("######### Run %d: (*function): %d"), (TInt)this, err);
				iLocalMsgQueue.SendBlocking(function);
				}
			}
				
		if(*iTerminateThread)
			CActiveScheduler::Stop();
		else
			Listen();
		
		}
	void DoCancel()
		{
		// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
		iMsgQueue.CancelDataAvailable();
		}
	};


void CWorkerThread::Rendezvous(TRequestStatus& aStatus)
	{
	iWorkerThread.Rendezvous(aStatus);
	}

TInt CWorkerThread::ThreadFunction(TAny* aPtr)
	{
	CWorkerThread* thread = (CWorkerThread*)aPtr;
	CTrapCleanup* cleanup = CTrapCleanup::New();
	CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
	CActiveScheduler::Install(scheduler);
	User::LeaveIfError( thread->iMsgQueue.CreateLocal(1024) );
	
	CThreadCallback* callback = new(ELeave) CThreadCallback(&thread->iTerminateThread, thread->iMsgQueue, thread->iLocalMsgQueue);
	
	(*thread->iInitFunction)();
	thread->iLocalMsgQueue.SendBlocking(thread->iInitFunction);
	
	callback->Listen();
	
	RThread::Rendezvous(KErrNone); // notify initialization	
	
	CActiveScheduler::Start();
	
	callback->Cancel();
	delete callback;
	
	thread->iMsgQueue.Close();
	
	delete scheduler;
	delete cleanup;
	
	}

void CWorkerThread::Execute( scalp::CFunction<void()>* aFunction )
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	{
	scalp::CFunction<void()>* function;
	while(iLocalMsgQueue.Receive(function) == KErrNone)
		{
		delete function;
		}
	}
	iMsgQueue.SendBlocking(aFunction);
	}


CWorkerThread::CWorkerThread()
	{
	}

CWorkerThread::~CWorkerThread()
	{
	}




struct CAsyncRequest_Local : public CActive
	{
	TBool iCancelled; // initially = EFalse;
	CWorkerThread* iWorkerThread;
	MAsyncRequestCallback* iCallback;
	CAsyncRequest* iRequest;
	TInt iPhase;
	CAsyncRequest_Local(CAsyncRequest* aRequest, CWorkerThread* aWorkerThread, MAsyncRequestCallback* aCallback) :
		CActive(EPriorityStandard), iWorkerThread(aWorkerThread),
		iRequest(aRequest), iCallback(aCallback)
	{
	CActiveScheduler::Add(this);
	}
	void RemoteCallbackWrapper(TThreadId aThreadId, TRequestStatus* aStatus)
		{
		// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
		iCallback->RemoteCallback();
		RThread thread;
		thread.Open(aThreadId);
		thread.RequestComplete(aStatus, KErrNone);
		thread.Close();
		}
	void RemoteCleanupWrapper(TThreadId aThreadId, TRequestStatus* aStatus)
		{
		// TFunTrace funTrace(__PRETTY_FUNCTION__); can't log, it's a remote thread
		iCallback->RemoteCleanup();
		RThread thread;
		thread.Open(aThreadId);
		thread.RequestComplete(aStatus, KErrNone);
		thread.Close();
		}

	void Start()
		{
		TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
		//TFunTrace funTrace(__PRETTY_FUNCTION__);
		iStatus = KRequestPending;
		SetActive();
		iWorkerThread->Execute( scalp::MakeFunctionL(scalp::Bind(&CAsyncRequest_Local::RemoteCallbackWrapper, this, RThread().Id(), &iStatus)) );
		}
	void LocalCancel()
		{
		TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
		//TFunTrace funTrace(__PRETTY_FUNCTION__);
		if(iPhase == 1)
			{
			
			}
		else
			{
			iCancelled = ETrue;
			iCallback->LocalCallback(KErrCancel);
			}
		}
	void DoCancel()
		{
		TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
		}
	void RunL()
		{
		TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
		//TFunTrace funTrace(__PRETTY_FUNCTION__);
		if(iPhase == 1)
			{
			delete iCallback;
			if(iRequest) iRequest->iLocal = NULL;
			delete this;
			}
		else
			{
			if(!iCancelled)
				{
				TRAPD(err, iCallback->LocalCallback(KErrNone));
				if(err != KErrNone)
					RDebug::Print(_L("######### Run %d: LocalCallback: %d"), (TInt)this, err);
				}
			iStatus = KRequestPending;
			SetActive();
			iWorkerThread->Execute( scalp::MakeFunctionL(scalp::Bind(&CAsyncRequest_Local::RemoteCleanupWrapper, this, RThread().Id(), &iStatus)) );
			iPhase = 1;
			}
		}
	};

void MAsyncRequestCallback::RemoteCallback()
{	
}
void MAsyncRequestCallback::LocalCallback(TInt aError)
{	
}
void MAsyncRequestCallback::RemoteCleanup()
{	
}
MAsyncRequestCallback::~MAsyncRequestCallback()
{	
}

CAsyncRequest::CAsyncRequest() : iLocal(NULL)
	{
	
	}

void CAsyncRequest::CallL(CWorkerThread* aWorkerThread, MAsyncRequestCallback* aCallback)
	{
	TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
	//TFunTrace funTrace(__PRETTY_FUNCTION__);
	iLocal = new (ELeave) CAsyncRequest_Local(this, aWorkerThread, aCallback);
	iLocal->Start();
	}
void CAsyncRequest::Cancel()
	{
	TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
	//TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iLocal)
		{
		iLocal->LocalCancel();
		iLocal->iRequest = NULL;
		iLocal = NULL;
		}
	}

CAsyncRequest::~CAsyncRequest()
	{
	TBuf8<256> buf; buf.Format(_L8("%s %d"), __PRETTY_FUNCTION__, (TInt)this); TFunTrace funTrace((const char*)buf.PtrZ());
	//TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iLocal)
		iLocal->iRequest = NULL;
	}
